package com.softserveinc.ita.kaiji.model.player;

import com.softserveinc.ita.kaiji.model.Card;
import com.softserveinc.ita.kaiji.model.Deck;
import com.softserveinc.ita.kaiji.model.DeckImpl;
import com.softserveinc.ita.kaiji.model.util.FiniteStateMachine;
import com.softserveinc.ita.kaiji.model.util.PlayerStates;
import org.apache.log4j.Logger;

/**
 * Represents basic real player and bot for future implementations
 * @author Ievgen Sukhov
 * @since 20.03.14
 * @version 1.5
 */

public abstract class AbstractPlayer implements Player , Comparable<Player> {

    protected Integer id;
    protected String name;
    protected Deck deck;
    protected Card chosenCard;
    protected Boolean canPlay;

    protected Logger logger = Logger.getLogger(getClass());

    protected FiniteStateMachine<PlayerStatus> statusChanger =
            new FiniteStateMachine<>(PlayerStatus.PLAYER_INITIALIZATION, PlayerStates.init());

    @Override
    public abstract void makeTurn(Card card);

    @Override
    public abstract Boolean isBot();


    @Override
    public Integer getId() {
        return id;
    }

    @Override
    public void setId(Integer id) {
        this.id = id;
    }

    @Override
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Deck getDeck() {
        return  this.deck;
    }

    public void setDeck(Integer cardNumber) {
        this.deck = new DeckImpl(cardNumber);
    }

    @Override
    public Card getChosenCard(){
        logger.info(this.name + " has chosen card: " + this.chosenCard);
        if (statusChanger.getCurrentState() == PlayerStatus.TURN_FINISHED) {
            return this.chosenCard;
        } else {
            statusChanger.switchState(PlayerStatus.PLAYER_BROKEN);
            throw new IllegalStateException("Can not get current card, wrong state");
        }
    }

    @Override
    public void commitTurn() {
        if (logger.isTraceEnabled()) {
            logger.trace("Commiting turn for " + this.name);
        }
       if (this.deck.getDeckSize()>0){
        if (statusChanger.canSwitchTo(PlayerStatus.TURN_READY)) {
            statusChanger.switchState(PlayerStatus.TURN_READY);
        } else {
            statusChanger.switchState(PlayerStatus.PLAYER_BROKEN);
            throw new IllegalStateException("Can not commit turn, wrong state!");
        }
       } else {
           if (statusChanger.canSwitchTo(PlayerStatus.FINISHED)) {
               statusChanger.switchState(PlayerStatus.FINISHED);
           } else {
               statusChanger.switchState(PlayerStatus.PLAYER_BROKEN);
               throw new IllegalStateException("Can not commit turn, wrong state");
           }
       }
        this.chosenCard = null;
    }

    @Override
    public void rollbackTurn() {
        if (statusChanger.getCurrentState() == PlayerStatus.TURN_FINISHED) {
            if (logger.isTraceEnabled()) {
                logger.trace("Making rollback for card: " + this.chosenCard);
            }
            deck.addCard(chosenCard);
            this.chosenCard = null;
            statusChanger.switchState(PlayerStatus.TURN_READY);
        }  else {
            statusChanger.switchState(PlayerStatus.PLAYER_BROKEN);
            throw new IllegalStateException("Can not rollback turn, wrong state");
        }
    }

    @Override
    public Integer getCardCount(){
        if (statusChanger.getCurrentState()!=PlayerStatus.PLAYER_BROKEN) {
            return deck.getDeckSize();
        } else {
            throw new IllegalStateException("Can not get deck size, wrong state");
        }
    }

    @Override
    public Boolean canPlay() {
        if (statusChanger.getCurrentState()!=PlayerStatus.PLAYER_BROKEN
                || statusChanger.getCurrentState()!=PlayerStatus.FINISHED) {
            return canPlay;
        } else {
            return false;
        }
    }

    @Override
    public void finish() {
        if (statusChanger.canSwitchTo(PlayerStatus.FINISHED)) {
            this.canPlay = false;
            statusChanger.switchState(PlayerStatus.FINISHED);
        } else {
            throw new IllegalStateException("Can not finish, player broken");
        }
    }

    @Override
    public PlayerStatus getState() {
        return statusChanger.getCurrentState();
    }

    @Override
    public String toString() {
        return this.name;
    }

    @Override
        public int compareTo(Player player) {
        return this.id.compareTo(player.getId());
    }


}
